Prizm Content Connect
Configuring PCC Imaging Services (PCCIS) Sample

PCCIS Services Sample

Why PCCIS was Introduced

The PCCIS product provides the same level of features as the original PCC product samples with respect to document conversion for web viewing but differs on architectural design. Rather than having separate web tier services for HTML5 and flash web applications, PCCIS handles request for both environments. The intent of the architecture is to remove the complexity away from a customer’s front end web tier into a separate service entity very much like the Proxy Server imaging services. The PCCIS will still depend on the Proxy Server for conversions but will implement faster mechanisms for supplying required information or new features for the clients. One strong benefit of this new product is the monitoring and managing of intermediate resources needed to supply the web clients with viewable data. There is a service that will log events for further analysis if issues of performance or failure should occur. An interface is available for monitoring the performance and robustness of the service by gathering information from the log.

Because PCCIS is a separate service entity from the customer’s web tier, source documents need to be uploaded to this service entity. The process requires two steps for the document upload. The first step is a notification step to PCCIS to expect a document (POST request) where it returns a unique identity to be used for subsequent actions. The second step is to upload (PUT request) the document data using the new identity string for the document identity. The new document identity (really Session Identification) is what the client PccViewer and Flash viewer control must use to view pages from the uploaded document. An important side note: if the upload cannot be successfully accomplished, there is an error abort process required as noted in the sample explanation.

The two steps must be executed by embedded code on the web page with a third post request operation triggering the server side conversion of viewable pages from the document in the desired view (html or flash). This request of view notification starts the conversion process as early as possible while the web page is being rendered by the browser. The result of this action will give a faster first page view experience.

While these three steps seem a little more complicated than the original PCC viewer samples, it alleviates the web tier sample work to just being a conduit of passing requests and responses. The application deals with a front end web tier communicating to a back end web tier which is performing all the complex work. Both html and flash work from the PCCIS and common web tier layer. Just the web page application dictates which protocol to use.

How to Use the PCCIS Services from a Web Application

Integrating code for a Prizm Application

The Prizm PCCIS sample demonstrates the use of a JavaScript component, pccViewer or flash viewer, which communicates with a web service using a RESTful scheme as noted in the Web Tier RESTful Web API topic. Before going into depth on the code pieces, the PCCIS Sample illustrates the various code pieces required to have a functional PCC application.

File

Description

App_Code Folder

Contains the supporting classes for the RESTful communication scheme between the pccViewer and web tier service. While the code body for the classes can be modified as needed, the APIs modifications need careful care if changed. See PCC.ashx. Most of the current web tier RESTful interface passes the request onto PCCIS services. This keeps the application web tier fairly easy to understand and maintain.

Js folder

Contains the required Javascript files making up the HTML5 pccViewer entity.

Images folder

Graphics for the HTML5 pccViewer.

Css folder

Web style sheet for the HTML5 pccViewer.

Default.aspx

The default web starting page in this sample. The pccViewer or flash viewer control would reside on the web application page.

PCC.ashx

File which defines and links the required prizm RESTful interface to the files in the App_Code folder. The client side Viewer Javascript object will use this RESTful interface as described in Web Tier RESTful Web API. File is required for the functionality of the IIS ASP.NET environment.

Settingsenterprise.xml

Contains the location of conversion helper files for Flash.

Swfobject.2.2.js

SWF (Flash) Objects Javascript Library.

ViewerEnterprise.swf

Flash Prizm viewer file.

Pcc.config

Contains modifiable parameter content locations for documents, cache folder and PCCIS connection. Replaces Prizmconfig.xml in non PCCIS samples.

Web.config

Contains IIS web tier settings.

Sample.doc

For the .Net sample, the test document used to illustrate the functional prizm content connect product.

 

Common Code for Both Viewer Protocols

While the flash viewer web page and HTML viewer page has some different code pieces, they share some pieces as well. As earlier noted, there is a two-step process to initiate the viewing application and to maximize performance; the first step is initiated on the Web application page. To accommodate the first step of uploading an image to PCCIS efficiently, some .NET assemblies need to be added to the web page.

PCCIS .NET Example 
Copy Code
<%@Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<%@Import Namespace="System.Net" %>
<%@Import Namespace="System.IO" %>
<%@Import Namespace="System.Web.Script.Serialization" %>
<%@Import Namespace="System.Threading.Tasks" %>

The following sample is essentially similar for both web pages accept for one line which identifies the preference for HTML or flash which will be highlighted in the code segment with left arrows. The process is to notify the PCCIS service that the application wishes to view a document. The following steps summarize the process only. The code sample provided gives a more elaborate explanation of the actual events to illicit a document viewing session:

  1. Use the PCCConfig file to point to the URL address for the PCCIS service via the web tier.
  2. Some identifying aspects of the document are collected (ipAddress, hostname and sourceDocument).
  3. Post the request to upload a document.
  4. Receive and collect the Document/Session Identification response to use for all further PCCIS service communication.
  5. Open and read the document contents into a stream object.
  6. Start a PUT request to the PCCIS service via the web tier URL.
  7. Copy the document data collected into the URL request stream.
  8. Initiate the upload request.
  9. If there is a problem at this stage, the PCCIS needs to be notified if this operation cannot be completed as illustrated in the sample try-catch exception handling.
To prevent attacks on viewing sessions, refer to the "Secure Viewing Sessions" section of the Security Guidance topic.

Another segment of the code intertwined in the sample involves kicking off PCCIS page conversion services after the document has been uploaded. That code piece does a POST to the SessionStarted URL. While seemingly a little more complicated than the previous samples, the viewing experience should be much more responsive than the previous PCC sample.

PCCIS .NET Example
Copy Code
<%       
    //--------------------------------------------------------------------
    //
    //  For this sample, the location to look for source documents
    //  specified only by name and the PCC Imaging Services (PCCIS) URL
    //  are configured in pcc.config.
    //
    //--------------------------------------------------------------------

    PccConfig.LoadConfig("pcc.config");

    JavaScriptSerializer serializer = new JavaScriptSerializer();
    string[] transferProtocols = { "http://", "https://", "ftp://" };
    string document = string.Empty;
    string viewingSessionId = string.Empty;

    string documentQueryParameter = Request.QueryString["document"];
    if (!string.IsNullOrEmpty(documentQueryParameter))
    {
        // Construct the full path to the source document
        if (transferProtocols.Any(documentQueryParameter.Contains))
        {
            document = documentQueryParameter;
        }
        else
        {
            document = Path.Combine(PccConfig.DocumentFolder, documentQueryParameter);
        }

        // Get the document's extension because PCCIS will need it later.
        string extension = System.IO.Path.GetExtension(document).TrimStart(new char[] { '.' }).ToLower();

        if (Path.IsPathRooted(document))
        {
            bool correctPath = PccConfig.IsFileSafeToOpen(document);
            if (!correctPath)
            {
                Response.Clear();
                Response.Write("<h1>403 Forbidden</h1>");
                Response.StatusCode = (int)System.Net.HttpStatusCode.Forbidden;
                return;
            }
        }

        // Request a new viewing session from PCCIS.
        //   POST http://localhost:18681/PCCIS/V1/ViewingSession
        //
        string uriString = string.Format("{0}/ViewingSession", PccConfig.ImagingService);
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriString);
        request.Method = "POST";
        using (StreamWriter requestStream = new StreamWriter(request.GetRequestStream(), Encoding.UTF8))
        {
            ViewingSessionProperties viewingSessionProperties = new ViewingSessionProperties();

            // Store some information in PCCIS to be retrieved later.
            viewingSessionProperties.externalId = CommonCode.Encoder.GetHashString(document);
            viewingSessionProperties.tenantId = "My User ID";

            // The following are examples of arbitrary information as key-value
            // pairs that PCCIS will associate with this document request.
            Dictionary<string, string> originInfo = new Dictionary<string, string>();
            originInfo.Add("ipAddress", Request.UserHostAddress);
            originInfo.Add("hostName", Request.UserHostName);
            originInfo.Add("sourceDocument", document);
            viewingSessionProperties.origin = originInfo;

            // Specify rendering properties.
            viewingSessionProperties.render = new RenderProperties() { flash = new FlashRenderProperties() { optimizationLevel = 1 }, html5 = new Html5RenderProperties { alwaysUseRaster = false } };

            // Serialize document properties as JSON which will go into the body of the request
            string requestBody = serializer.Serialize(viewingSessionProperties);
            requestStream.Write(requestBody);
        }

        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        string responseBody = null;
        using (StreamReader sr = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8))
        {
            responseBody = sr.ReadToEnd();
        }

        // Store the ID for this viewing session that is returned by PCCIS
        Dictionary<string, object> responseValues = (Dictionary<string, object>)serializer.DeserializeObject(responseBody);
        viewingSessionId = responseValues["viewingSessionId"].ToString();

        // Get the user agent from the Request object so we can send to PCCIS in the background thread.
        // PCCIS uses this information to determine support for SVG and logging purposes.
        string userAgent = Request.Headers["User-Agent"];

        // Use a background thread to send the document to PCCIS and begin a viewing session.
        // This allows the current web page to finish loading and the PCC viewer to appear sooner.
        Task notificationTask = new Task(() =>
        {
            Stream documentStream = null;
            try
            {
                // Open the source document
                if (transferProtocols.Any(document.Contains))
                {
                    // Download the source document to memory if it's a remote document. The document
                    // data will be uploaded to PCCIS soon after.
                    HttpWebRequest fileRequest = (HttpWebRequest)HttpWebRequest.Create(document);
                    HttpWebResponse fileResponse = (HttpWebResponse)fileRequest.GetResponse();

                    using (Stream responseStream = fileResponse.GetResponseStream())
                    {
                        documentStream = new MemoryStream();
                        responseStream.CopyTo(documentStream);
                        documentStream.Seek(0, SeekOrigin.Begin);
                    }
                }
                else
                {
                    documentStream = new FileStream(document, FileMode.Open, FileAccess.Read);
                }

                // Upload File to PCCIS.
                //   PUT http://localhost:18681/PCCIS/V1/ViewingSessions/u{ViewingSessionID}/SourceFile?FileExtension={FileExtension}
                // Note the "u" prefixed to the Viewing Session ID. This is required when providing
                //   an unencoded Viewing Session ID, which is what PCCIS returns from the initial POST.
                //    
                uriString = string.Format("{0}/ViewingSession/u{1}/SourceFile?FileExtension={2}", PccConfig.ImagingService, viewingSessionId, HttpUtility.UrlEncode(extension));
                request = (HttpWebRequest)WebRequest.Create(uriString);
                request.Method = "PUT";
                using (Stream requestStream = request.GetRequestStream())
                {
                    documentStream.CopyTo(requestStream);
                }
                response = (HttpWebResponse)request.GetResponse();

                // Start Viewing Session in PCCIS.
                //   POST http://localhost:18681/PCCIS/V1/ViewingSessions/u{ViewingSessionID}/Notification/SessionStarted
                //   
                uriString = string.Format("{0}/ViewingSession/u{1}/Notification/SessionStarted", PccConfig.ImagingService, viewingSessionId);
                request = (HttpWebRequest)WebRequest.Create(uriString);
                request.Method = "POST";
                request.UserAgent = userAgent;
                using (Stream requestStream = request.GetRequestStream())
                {
                    using (TextWriter requestStreamWriter = new StreamWriter(requestStream))
                    {
                        serializer = new JavaScriptSerializer();

                      // USE the Desired viewer type here!!!!
                        string requestBody = serializer.Serialize(new { viewer = "HTML5" });
                      //     OR
                        string requestBody = serializer.Serialize(new { viewer = "Flash" });
                     //
                        requestStreamWriter.Write(requestBody);
                    }
                }
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (Exception ex)
            {
                // If a problem was encountered in the background thread, notify PCCIS
                // that the session should be stopped so it can return appropriate status
                // to the viewer requests made to it.
                //   POST http://localhost:18681/PCCIS/V1/ViewingSessions/u{ViewingSessionID}/Notification/SessionStopped
                //
                uriString = string.Format("{0}/ViewingSession/u{1}/Notification/SessionStopped", PccConfig.ImagingService, viewingSessionId);
                request = (HttpWebRequest)WebRequest.Create(uriString);
                request.Method = "POST";
                using (Stream requestStream = request.GetRequestStream())
                {
                    using (TextWriter requestStreamWriter = new StreamWriter(requestStream))
                    {
                        string requestBody = serializer.Serialize(new { endUserMessage = ex.Message, httpStatus = 504 });
                        requestStreamWriter.Write(requestBody);
                    }
                }
                response = (HttpWebResponse)request.GetResponse();
            }
            finally
            {
                if (documentStream != null)
                {
                    documentStream.Dispose();
                }
            }
        });
        notificationTask.Start();
    }
    else
    {
        viewingSessionId = Request.QueryString["viewingSessionId"];
        if (!string.IsNullOrEmpty(viewingSessionId))
        {
            // If there was no 'document' parameter, but a 'viewingSessionId'
            // value exists, there is a viewing session already so we don't
            // need to do anything else. This case is true when viewing attachments
            // of email message document types (.EML and .MSG).

            // Request properties about the viewing session from PCCIS.
            // The properties will include an identifier of the source document
            // from which the attachment was obtained. The name of the attachment
            // is also available. These values are used to just to provide
            // contextual information to the user.
            //   GET http://localhost:18681/PCCIS/V1/ViewingSession/u{ViewingSessionID}
            //
            string uriString = string.Format("{0}/ViewingSession/u{1}", PccConfig.ImagingService, viewingSessionId);
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uriString);
            request.Method = "GET";
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            string responseBody = null;
            using (StreamReader sr = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8))
            {
                responseBody = sr.ReadToEnd();
            }
            ViewingSessionProperties viewingSessionProperties = serializer.Deserialize<ViewingSessionProperties>(responseBody);
            document = viewingSessionProperties.origin["sourceDocument"] + ":{" + viewingSessionProperties.attachmentDisplayName + "}";
        }
        else
        {
            Response.Write("You must include the name of a document in the URL.<br/>");
            Response.Write("For example, click on this link: <a href=\"Default.aspx?document=sample.doc\">Default.aspx?document=sample.doc</a>");
            return;
        }
    }
%>

After this code segment, the two viewers diverge to accommodate the HTML5 viewer or Flash viewer. Basically, the appropriate JavaScript files and CSS files are setup in the html page statements along with the appropriate control references. After those differences, the pages share a common JavaScript and html piece for handling and displaying EML and MSG attachments and information about web page application resources.

HTML5 Web Page Segment

PCCIS .NET Example
Copy Code
<!DOCTYPEhtml>
<htmlxmlns="http://www.w3.org/1999/xhtml">
<headid="Head1" runat="server">
    <title>PCC HTML5 .NET C# Sample</title>
    <link rel="icon" href="favicon.ico" type="image/x-icon" />
    <link href="../Default.css" rel="stylesheet" type="text/css"/>
    <script src="js/jquery-1.7.2.min.js" type="text/javascript"></script>
    <script src="js/jquery-ui-1.8.21.custom.min.js" type="text/javascript"></script>
    <script src="js/pccViewer.js" type="text/javascript"></script>
</head>
<body>
    <script type="text/javascript">
        var viewingSessionId = '<%=HttpUtility.JavaScriptStringEncode(viewingSessionId)%>';

        $(document).ready(function () {
            var pluginOptions1 = {
                documentID: viewingSessionId,
                toolboxMenuOpen: false,
                annotationID: 'Annotation Filename',
                imageHandlerUrl: "../pcc.ashx",
                uiElements: { toolTips: true, fullScreenToggle: true, firstLastPage: false} }
            $("#imageGearPageView").pccViewer(pluginOptions1);
        });

        // The following javascript will process any attachments for the
        // email message document types (.EML and .MSG).
        setTimeout(requestAttachments, 500);

        var countOfAttachmentsRequests = 0;

        function receiveAttachments(data, textStatus, jqXHR) {
            if (data == null || data.status != 'complete') {
                // The request is not complete yet, try again after a short delay.
                setTimeout(requestAttachments, countOfAttachmentsRequests * 1000);
            }

            if (data.attachments.length > 0) {
                var links = '';
                for (var i = 0; i < data.attachments.length; i++) {
                    var attachment = data.attachments[i];
                    links += '<a href=\?viewingSessionId=' + attachment.viewingSessionId + '>' + attachment.displayName + '</a><br/>';
                }

                $('#attachmentList').html(links);
                $('#attachments').show();
            }
        }

        function requestAttachments() {
            if (countOfAttachmentsRequests < 10) {
                countOfAttachmentsRequests++;
                $.ajax('../pcc.ashx/ViewingSession/u' + viewingSessionId + '/Attachments', { dataType: 'json' }).done(receiveAttachments).fail(requestAttachments);
            }
        }
    </script>
    <div id="infocontent">
        <div class="header" >
            <p>Accusoft Corporation Prizm Content Connect .NET C# Sample</p>
        </div>
        <div class="item border_btm">
            <p>
                <b>FAQ: </b><a href="http://www.accusoft.com/prizmfaq.htm" target="_blank">http://www.accusoft.com/prizmfaq.htm</a>
            </p>                           
        </div>
        <div class="item border_btm">
            <h1>Configuration Properties</h1>
            <div class="datagrid"><table>
                    <tbody>
                        <tr>
                            <td>Viewer URL</td>
                            <td><%="<a href='" + Request.Url.AbsoluteUri + "'>" + Request.Url.AbsoluteUri + "</a>"%></td>
                        </tr>
                        <tr><td>Full Document Path</td><td><%=document%></td></tr>
                        <tr><td>Server Documents Directory<b>*</b></td><td><%=PccConfig.DocumentFolder%></td></tr>
                        <tr><td>Server Annotations Directory<b>*</b></td><td><%=PccConfig.MarkupFolder%></td></tr>
                    </tbody>
                </table>
            </div>
            <h2>*If you have trouble viewing a document or annotation, verify that these properties are set appropriately in pcc.config.</h2>
        </div> 
    </div>
    <div id="imageGearViewer">
        <div id="imageGearPageView">
        </div>
    </div>
    <br /><br />
    <p id="attachments" style="display:none;">
    <b>Attachments:</b>
    <p id="attachmentList">
    </p>
    </p>
</body>
</html>

Flash Web Page Segment

PCCIS .NET Example
Copy Code
<htmlxmlns="http://www.w3.org/1999/xhtml">
<headid="Head1" runat="server">
    <link rel="icon" href="favicon.ico" type="image/x-icon" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>PCC Flash .NET C# Sample</title>   
    <link href="../Default.css" rel="stylesheet" type="text/css"/>
    <script src="swfobject.2.2.js" language="javascript"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
</head>
<body>
    <script type="text/javascript">
        var encodedViewingSessionId = '<%=CommonCode.Encoder.EncodeURLString(viewingSessionId)%>';

        var params = {
            wmode: 'opaque',
            scale: 'noscale',
            allowFullScreen: true,
            allowScriptAccess: 'always',
            bgcolor: '#ffffff'
        };
        var attributes = {
            id: 'ViewerEnterpriseAnnotation',
            name: 'ViewerEnterpriseAnnotation'
        };
        var flashvars = {
            documentname: encodedViewingSessionId,
            saveDocumentLocation: '../pcc.ashx/FlashViewer/SaveDocument?document=' + encodedViewingSessionId
        };
        if (swfobject.getFlashPlayerVersion().major == 0) {
            var alternateContent = ''
                + '<div id="documentviewer">\n'
                + '  The Prizm Content Connect viewer requires Adobe Flash player.\n'
                + '  <p>\n'
                + '    <a href="http://get.adobe.com/flashplayer/"><img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player"/></a>\n'
                + '  </p>\n'
                + '</div>';
            document.write(alternateContent);
        }
        swfobject.embedSWF("ViewerEnterpriseAnnotation.swf", "documentviewer", "800", "650", "10.0.0", false, flashvars, params, attributes);
       
        // The following javascript will process any attachments for the
        // email message document types (.EML and .MSG).
        setTimeout(requestAttachments, 500);

        var countOfAttachmentsRequests = 0;

        function receiveAttachments(data, textStatus, jqXHR) {
            if (data == null || data.status != 'complete') {
                // The request is not complete yet, try again after a short delay.
                setTimeout(requestAttachments, countOfAttachmentsRequests * 1000);
            }

            if (data.attachments.length > 0) {
                var links = '';
                for (var i = 0; i < data.attachments.length; i++) {
                    var attachment = data.attachments[i];
                    links += '<a href=\?viewingSessionId=' + attachment.viewingSessionId + '>' + attachment.displayName + '</a><br/>';
                }

                $('#attachmentList').html(links);
                $('#attachments').show();
            }
        }

        function requestAttachments() {
            if (countOfAttachmentsRequests < 10) {
                countOfAttachmentsRequests++;
                $.ajax('../pcc.ashx/ViewingSession/u' + encodedViewingSessionId + '/Attachments', { dataType: 'json' }).done(receiveAttachments).fail(requestAttachments);
            }
        }
    </script>
    <noscript>
        Javascript needs to be enabled to view the document in viewer.
    </noscript>
    <div id="infocontent">
        <div class="header" >
            <p>Accusoft Corporation Prizm Content Connect .NET C# Sample</p>
        </div>
        <div class="item border_btm">
            <p>
                <b>FAQ: </b><a href="http://www.accusoft.com/prizmfaq.htm" target="_blank">http://www.accusoft.com/prizmfaq.htm</a>
            </p>                           
        </div>
        <div class="item border_btm">
            <h1>Configuration Properties</h1>
            <div class="datagrid"><table>
                    <tbody>
                        <tr>
                            <td>Viewer URL</td>
                            <td><%="<a href='" + Request.Url.AbsoluteUri + "'>" + Request.Url.AbsoluteUri + "</a>"%></td>
                        </tr>
                        <tr><td>Full Document Path</td><td><%=document%></td></tr>
                        <tr><td>Server Documents Directory<b>*</b></td><td><%=PccConfig.DocumentFolder%></td></tr>
                        <tr><td>Server Annotations Directory<b>*</b></td><td><%=PccConfig.MarkupFolder%></td></tr>
                    </tbody>
                </table>
            </div>
            <h2>*If you have trouble viewing a document or annotation, verify that these properties are set appropriately in pcc.config.</h2>
        </div> 
    </div>
    <div id="documentviewer">
    </div>
    <br />
    <p id="attachments" style="display:none;">
    <b>Attachments:</b>
    <p id="attachmentList">
    </p>
    </p>
</body>
</html>

Additional Differences from the Non-PCCIS Samples

While there are many aspects similar to the PCC samples not using PCCIS, some environmental information and configuration choices have been repackaged into the pcc.config file from the prizmconfig.xml file for the PCCIS sample. The content is essentially the same as before but should add security protection for environments not allowing access to this type of file such as Windows IIS.

See Also

 

 


©2014. Accusoft Corporation. All Rights Reserved.

Send Feedback